package com.minivision.fdiot.mqtt.serialize.msgpack;

import java.io.IOException;

import org.msgpack.MessagePack;
import org.msgpack.annotation.Message;

import com.minivision.fdiot.protopool.CodecException;
import com.minivision.fdiot.protopool.BinaryBody;
import com.minivision.fdiot.mqtt.protocol.SpringContextUtil;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * msgpack序列化
 * @author hughzhao
 * @2018年3月2日
 * @param <T>
 */
@Getter
@Setter
@ToString
public abstract class MsgPackBody<T> extends BinaryBody {

  private static final long serialVersionUID = -3825816130166157892L;

  protected T data;
  
  @Override
  public byte[] encode() throws CodecException {
    if (data == null) {
      return new byte[0];
    }
    MessagePack msgpack = null;
    if (SpringContextUtil.getApplicationContext() != null) {
      msgpack = SpringContextUtil.getBean(MessagePack.class);
    } else {
      msgpack = new MessagePack();
    }

    if (!data.getClass().isAnnotationPresent(Message.class)) {
      msgpack.register(data.getClass());
    }
    try {
      return msgpack.write(data);
    } catch (IOException e) {
      throw new CodecException("Encode failed due to " + e.getMessage(), e);
    }
  }
  
  @Override
  public BinaryBody decode(byte[] bytes) throws CodecException {
    MessagePack msgpack = null;
    if (SpringContextUtil.getApplicationContext() != null) {
      msgpack = SpringContextUtil.getBean(MessagePack.class);
    } else {
      msgpack = new MessagePack();
    }
    
    Class<T> clazz = getType();
    if (!clazz.isAnnotationPresent(Message.class)) {
      msgpack.register(clazz);
    }
    
    try {
      this.data = msgpack.read(bytes, clazz);
    } catch (IOException e) {
      throw new CodecException("Decode failed due to " + e.getMessage(), e);
    }
    return this;
  }
  
  public abstract Class<T> getType();

}
